﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Web;
using WinServiceBase;
using WinServiceBase.Utils;

namespace WinServiceBase.Utils
{
    public static class IQueryableExtensions
    {
        public static void Foreach<T>(this IQueryable<T> queryList, Action<T> toDo)
        {
            foreach(T curT in queryList)
                toDo.Invoke(curT);
        }
    }

    public static class IEnumerableExtensions
    {
        public static void Foreach<T>(this IEnumerable<T> queryList, Action<T> toDo)
        {
            foreach(T curT in queryList)
                toDo.Invoke(curT);
        }
        public static string Join(this IEnumerable data, Func<object, int, string> strRep, string separator, bool ignoreEmpties)
        {
            StringBuilder strBuilder = new StringBuilder();
            IEnumerator enumtor = data.GetEnumerator();
            int index = 0;
            if(enumtor.MoveNext())
            {
                string currStr = strRep(enumtor.Current, index);
                if(!string.IsNullOrEmpty(currStr) || !ignoreEmpties)
                    strBuilder.Append(currStr);

                while(enumtor.MoveNext())
                {
                    index++;
                    currStr = strRep(enumtor.Current, index);
                    if(ignoreEmpties && string.IsNullOrEmpty(currStr))
                        continue;

                    if(strBuilder.Length > 0)
                        strBuilder.Append(separator);

                    strBuilder.Append(currStr);
                }
            }

            return strBuilder.ToString();
        }
        public static string Join(this IEnumerable data, string separator, bool ignoreEmpties)
        {
            return Join(data, (x, indx) => x + "", separator, ignoreEmpties);
        }
        public static string Join(this IEnumerable data, string separator)
        {
            return data.Join(separator, true);
        }
        public static string Join(this IEnumerable data)
        {
            return data.Join(", ");
        }
        public static string ToCsvLine(this IEnumerable values, bool quoteall)
        {
            return values.Join((val, indx) => GetCsvItem(val, quoteall), ",", false);
        }

        private static string GetCsvItem(object item, bool quoteall)
        {
            if(item == null)
                return "";

            string result = item.ToString();
            if(quoteall || result.IndexOfAny("\",\x0A\x0D".ToCharArray()) > -1)
                result = "\"" + result.Replace("\"", "\"\"") + "\"";

            return result;
        }
    }

    public static class IDictionaryExtensions
    {
        public static Dictionary<TValue, TValue> JustValues<TKey, TValue>(this Dictionary<TKey, TValue> instance)
        {
            Dictionary<TValue, TValue> result = new Dictionary<TValue, TValue>(instance.Count);
            instance.Foreach(curPair =>
            {
                if(!result.ContainsKey(curPair.Value))
                    result.Add(curPair.Value, curPair.Value);
            });

            return result;
        }
        public static Dictionary<TKey, TKey> JustKeys<TKey, TValue>(this Dictionary<TKey, TValue> instance)
        {
            Dictionary<TKey, TKey> result = new Dictionary<TKey, TKey>(instance.Count);
            instance.Foreach(curPair => result.Add(curPair.Key, curPair.Key));

            return result;
        }
    }

    public static class StringExtensions
    {
        public const string EmailRegex = @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
    }

    public static class NumberExtension
    {
        public static readonly string[] StorageUnits = new string[] { "bytes", "Kb", "Mb", "Gb", "Tb" };
        public static string AsStorageUnit(this UInt64 bytes)
        {
            double unitVal = 0;
            var unit = StorageUnits[0];

            if(bytes != 0)
            {
                var log = Math.Log(bytes, 1024);
                unit = StorageUnits[Math.Min(StorageUnits.Length - 1, (int)log)];
                unitVal = Math.Round(((double)bytes / (double)(Math.Pow(1024, (int)log))), 2);
            }

            return unitVal + unit;
        }
    }

    public static class DateAndTimeExtensions
    {
        public static string VerboseFormat(this TimeSpan time)
        {
            string result = "";

            if(time.Days > 0)
                result += time.Days > 1 ? time.Days + " días, " : time.Days + " día, ";
            if(time.Hours > 0)
                result += time.Hours > 1 ? time.Hours + " horas, " : time.Hours + " hora, ";
            if(time.Minutes > 0)
                result += time.Minutes + " min, ";
            if(time.Seconds > 0)
                result += time.Seconds + " seg";

            if(result == "")
                result = time.Milliseconds + " mlseg";
            else if(result.EndsWith(", "))
                result = result.Substring(0, result.Length - 2);

            return result;
        }
    }

    public static class LogService
    {
        private static bool logging = true;

        public static void Start()
        {
            logging = true;
        }
        public static void Stop()
        {
            logging = false;
        }

        public static void LogToConsole(params string[] lines)
        {
            if(logging)
                lines.Foreach(curLine => Console.WriteLine(curLine));
        }
        public static void LogToFile(string logsFile, params string[] lines)
        {
            if(logging && !string.IsNullOrEmpty(logsFile) && lines.Length > 0)
            {
                if(Directory.Exists(Path.GetDirectoryName(logsFile)))
                {
                    string curLine = string.Format("[{0}]: {1}{2}", DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt"), lines[0], Environment.NewLine);
                    File.AppendAllText(logsFile, curLine);
                    for(int i = 1; i < lines.Length; i++)
                    {
                        curLine = string.Format("{0}{1}", lines[i], Environment.NewLine);
                        File.AppendAllText(logsFile, curLine);
                    }
                }
            }
        }
    }
}